/*
  Copyright © 2010  Vinícius dos Santos Oliveira
  Copyright © 2010  Camilo Costa Campos

      This file is part of Touché.

      Touché is free software: you can redistribute it and/or modify
      it under the terms of the GNU Lesser General Public License as published
      by the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU Lesser General Public License for more details.

      You should have received a copy of the GNU Lesser General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */

#include "colaborativecontroller.h"

#include "colaborative/dialog.h"
#include <QGraphicsView>
#include "stageactor.h"
#include "stage.h"
#include "stageactorlink.h"

#define TOUCHE_SHOULD_SKIP_THIS

#include "elements/textelement.h"
#include "elements/scribbleelement.h"
#include "elements/audioelement.h"
#include "elements/photoelement.h"

#undef TOUCHE_SHOULD_SKIP_THIS

using namespace Touche;

inline Element *makeElement(const QString &type)
{
    if(type == "audio"){
        return new AudioElement;
    }else if(type == "photo"){
        return new PhotoElement;
    }else if(type == "scribble"){
        return new ScribbleElement;
    }else if(type == "text"){
        return new TextElement;
    }else{
        qDebug("Eu não dou a luz a este tipo de elemento");
        return NULL;
    }
}

ColaborativeController *ColaborativeController::master = NULL;

ColaborativeController *ColaborativeController::getInstance(Stage *stage, QGraphicsScene *scene)
{
    if(master){
        return master;
    }else{
        return master = new ColaborativeController(stage, scene);
    }
}

ColaborativeController::ColaborativeController(Stage *stage, QGraphicsScene *scene) :
        scene(scene),
        startButton(new PushButtonItem(":/gfx/svg/icon_share.svg")),
        manager(new ColaborativeManager(this)),
        mainDialog(new ColaborationWindow(manager)),
        stage(stage)
{
    startButton->setPos(734., 108.);
    scene->addItem(startButton);
    connect(startButton, SIGNAL(clicked()), this, SLOT(start()));


    //connects of colaborative controler to manager
    connect(this, SIGNAL(addElement(Touche::Element*)), this->manager, SLOT(onElementAddedByMe(Touche::Element*)));
    connect(this, SIGNAL(addLink(QUuid,QUuid)), this->manager, SLOT(onLinkAddedByMe(QUuid,QUuid)));
//    connect(this, SIGNAL(startEditingMyElement(QUuid)), this->manager, SLOT(onStartEditingByMe(QUuid)));
//    connect(this, SIGNAL(finishEditingMyElement(QUuid)), this->manager, SLOT(onFinishEditingByMe(QUuid)));

    //connects of manager to colaborative controler
    connect(this->manager, SIGNAL(elementAdded(QUuid,QString,QString,QString)), this, SLOT(onElementAdded(QUuid,QString,QString,QString)));
    connect(this->manager, SIGNAL(linkAdded(QUuid,QUuid)), this, SLOT(onLinkAdded(QUuid,QUuid)));
    connect(this->manager, SIGNAL(elementModified(QUuid,QString,QStringList)), this, SLOT(onElementModified(QUuid,QString,QStringList)));
    connect(this->manager, SIGNAL(elementRemoved(QUuid)), this, SLOT(onElementRemoved(QUuid)));

    connect(this->manager, SIGNAL(startEditing(QUuid)), this, SLOT(onStartEditing(QUuid)));
    connect(this->manager, SIGNAL(finishEditing(QUuid)), this, SLOT(onFinishEditing(QUuid)));
    connect(this->manager, SIGNAL(messageReceived(QXmppMessage)), &reader, SLOT(onMessageReceived(QXmppMessage)));
    connect(&reader, SIGNAL(chatText(QString)), mainDialog, SLOT(onChatText(QString)));
    connect(&reader, SIGNAL(elementReceived(QUuid,QString,QString,QString)), this, SLOT(onElementAdded(QUuid,QString,QString,QString)));
    connect(&reader, SIGNAL(linkReceived(QUuid, QUuid)), this, SLOT(onLinkAdded(QUuid,QUuid)));
    connect(&reader, SIGNAL(lockElement(QUuid)), this, SLOT(onStartEditing(QUuid)));
    connect(&reader, SIGNAL(unlockElement(QUuid)), this, SLOT(onFinishEditing(QUuid)));


}

ColaborativeController::~ColaborativeController()
{
    delete mainDialog;
}

void ColaborativeController::colaborateElement(Touche::Element *element)
{
    emit addElement(element);
}

void ColaborativeController::colaborateLink(const QUuid &src, const QUuid &dst)
{
    emit addLink(src, dst);
}

void ColaborativeController::start()
{
    if(!manager->isConnected()){
//        QDialog *dialog = new Dialog(this->manager, scene->views().first());
//        dialog->setGeometry(128, 128, 544, 224);
//        dialog->exec();

        if((new Dialog(this->manager))->exec()){
            mainDialog->show();
        }
    }else{
        mainDialog->show();
    }
}

void ColaborativeController::onStartEditing(const QUuid &uuid)
{
        // TODO impedir a edição do objeto uuid
    if(Element *element =  StageActor::elements()[uuid]){
        StageActor::getActor(element)->onElementLocked(true);
    }
}

void ColaborativeController::onFinishEditing(const QUuid &uuid)
{
    // TODO permitir a edição do objeto uuid
    if(Element *element =  StageActor::elements()[uuid]){
        StageActor::getActor(element)->onElementLocked(false);
    }
}

void ColaborativeController::onElementAdded(const QUuid &uuid, const QString &type, const QString &xml, const QString &file)
{
    if(Element *element = StageActor::elements()[uuid]){
        element->load(xml, file);
    }else{
        if(Element *element = makeElement(type)){
            element->load(xml, file);
            const_cast<QUuid &>(element->id) = uuid;
            stage->addToGroup(element);
            qDebug() << "recebendo elemento da casa da mãe joana" << element->id;
        }
    }
}

void ColaborativeController::onLinkAdded(const QUuid &first, const QUuid &second)
{
    const QHash<QUuid, Element *> &elements(StageActor::elements());
    StageActor *actors[2] = {StageActor::getActor(elements[first]), StageActor::getActor(elements[second])};
    if(actors[0] && actors[1]){
        if(!StageActorLink::exists(actors[0], actors[1])){
            StageActorLink *link = new StageActorLink(actors[0], actors[1]);
            actors[0]->links.append(link);
            actors[1]->links.append(link);
        }
    }else{
        qDebug("erro: link envolvendo elementos que eu não tenho");
    }
}

void ColaborativeController::onElementRemoved(const QUuid &uuid)
{
    // TODO
}

void ColaborativeController::onElementModified(const QUuid &uuid, const QString &xml, const QStringList &listFiles)
{
    // TODO
}
void ColaborativeController::lockElement(Element *element)
{
    manager->lockElement(element->id);
}

void ColaborativeController::unlockElement(Element *element)
{
    manager->unlockElement(element->id);
}

void ColaborativeController::onElementLocked(const QUuid &uuid)
{
    // TODO
}

void ColaborativeController::onElementUnlocked(const QUuid &uuid)
{
    // TODO
}
